package yunjiao.javatutorials.guava.concurrent.log;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 数据库连接池监控
 *
 * @author yangyunjiao
 */
public class DatabaseConnectionPool {
    private final LoggingLock poolLock;
    private final Condition connectionAvailableCondition;
    private final List<Connection> availableConnections;
    private final List<Connection> usedConnections;

    public DatabaseConnectionPool(int poolSize) {
        this.poolLock = new LoggingLock(new ReentrantLock(true), "DBConnectionPool");
        this.connectionAvailableCondition = poolLock.newCondition();
        this.availableConnections = new ArrayList<>();
        this.usedConnections = new ArrayList<>();

        // 初始化连接池
        for (int i = 0; i < poolSize; i++) {
            availableConnections.add(new Connection("Connection-" + i));
        }
    }

    public Connection getConnection() throws InterruptedException {
        poolLock.lock();
        try {
            while (availableConnections.isEmpty()) {
                System.out.println("等待数据库连接...");
                connectionAvailableCondition.await(100, TimeUnit.MILLISECONDS);
            }

            Connection conn = availableConnections.remove(0);
            usedConnections.add(conn);
            System.out.println("获取连接: " + conn.getId());
            return new ProxyConnection(conn, this);
        } finally {
            poolLock.unlock();
        }
    }

    private void returnConnection(Connection conn) {
        poolLock.lock();
        try {
            usedConnections.remove(conn);
            availableConnections.add(conn);
            System.out.println("归还连接: " + conn.getId());
            connectionAvailableCondition.signal();
        } finally {
            poolLock.unlock();
        }
    }

    // 代理连接类，在关闭时自动归还到连接池
    private class ProxyConnection extends Connection {
        private final Connection realConnection;
        private final DatabaseConnectionPool pool;

        public ProxyConnection(Connection realConnection, DatabaseConnectionPool pool) {
            super(realConnection.getId());
            this.realConnection = realConnection;
            this.pool = pool;
        }

        @Override
        public void close() {
            pool.returnConnection(realConnection);
        }

        @Override
        public void executeQuery(String sql) {
            realConnection.executeQuery(sql);
        }
    }

    // 模拟数据库连接
    static class Connection {
        private final String id;

        public Connection(String id) {
            this.id = id;
        }

        public String getId() { return id; }

        public void executeQuery(String sql) {
            System.out.println(id + " 执行: " + sql);
        }

        public void close() {
            // 基础实现
        }
    }

    public static void main(String[] args) throws InterruptedException {
        DatabaseConnectionPool pool = new DatabaseConnectionPool(2);
        ExecutorService executor = Executors.newFixedThreadPool(4);

        for (int i = 0; i < 5; i++) {
            final int taskId = i;
            executor.submit(() -> {
                try {
                    Connection conn = pool.getConnection();
                    try {
                        conn.executeQuery("SELECT * FROM table_" + taskId);
                        Thread.sleep(500); // 模拟查询时间
                    } finally {
                        conn.close();
                    }
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            });
        }

        executor.shutdown();
        executor.awaitTermination(10, TimeUnit.SECONDS);
    }
}
